package com.jh.fcsm.common.aspect;

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.jh.fcsm.common.annotation.DecryptField;
import com.jh.fcsm.constant.TokenConstants;
import com.jh.fcsm.enums.DesTypeEnum;
import com.jh.fcsm.util.security.DesensitizedUtils;
import com.jh.fcsm.util.txt.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;
@Component
@Aspect
public class EncryptDecryptAop {
    private static final Logger logger = LoggerFactory.getLogger(EncryptDecryptAop.class);
    /**
     * 定义需要解密的切入点
     */
    @Pointcut(value = "execution(* com.jh.*.dao.*.*Mapper.*(..))")
    public void point() {
    }
    /**
     * 命中的切入点时的环绕通知
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("point()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //加密逻辑
        //执行目标方法
        Object result = EncryptAop.around(proceedingJoinPoint);
        //判断目标方法的返回值类型
        if (result instanceof List) {
            for (Object tmp : ((List) result)) {
                //数据脱敏处理逻辑
                this.deepProcess(tmp);
            }
        } else {
            this.deepProcess(result);
        }
        return result;
    }

    public void deepProcess(Object obj) throws Exception {
        if (obj != null) {
            //取出输出对象的所有字段属性，并遍历
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                //判断字段属性上是否标记DecryptField注解
                if (declaredField.isAnnotationPresent(DecryptField.class)) {
                    //如果判断结果为真，则取出字段属性数据进行解密处理
                    declaredField.setAccessible(true);
                    Object valObj = declaredField.get(obj);
                    if (valObj != null) {
                        DecryptField annotation = declaredField.getAnnotation(DecryptField.class);
                        String value = valObj.toString();
                        //加密数据的解密处理
                        if(annotation.isEncryptField()) {
                            value = this.decrypt(value);
                        }
                        if(annotation.isDes()){
                            value=desensitization(value,annotation.desType());
                        }
                        //把解密后的数据重新赋值
                        declaredField.set(obj, value);
                    }
                }
            }
        }
    }

    private String desensitization(String value, DesTypeEnum desTypeEnum) {
        String result="";
        if (StringUtils.isNotBlank(value) && null != desTypeEnum){
            switch (desTypeEnum) {
                case CHINESE_NAME:
                    result = DesensitizedUtils.chineseName(value);
                    break;
                case ID_CARD:
                    result = DesensitizedUtils.idCardNum(value);
                    break;
                case FIXED_PHONE:
                    result = DesensitizedUtils.fixedPhone(value);
                    break;
                case MOBILE_PHONE:
                    result = DesensitizedUtils.mobilePhone(value);
                    break;
                case ADDRESS:
                    result = DesensitizedUtils.address(value);
                    break;
                case EMAIL:
                    result = DesensitizedUtils.email(value);
                    break;
                case BANK_CARD:
                    result = DesensitizedUtils.bankCard(value);
                    break;
                case PASSWORD:
                    result = DesensitizedUtils.password(value);
                    break;
                case KEY:
                    result = DesensitizedUtils.key(value);
                    break;
                case NO:
                    result = value;
                    break;
                default:
                    throw new IllegalArgumentException("Unknow sensitive type enum " + desTypeEnum.name());
            }
        }
        return result;
    }

    private String decrypt(String value) throws Exception {
        SymmetricCrypto sm4 = SmUtil.sm4(TokenConstants.SM4_DATA_SECRET.getBytes());
        return sm4.decryptStr(value);//库加密结果
    }

}